03 - Authentication-&-GitHub-Integration
Relevant source files
Purpose and ScopeLink copied!
This page documents the authentication and GitHub integration architecture for godeep.wiki, which implements a dual authentication system:
- User OAuth tokens: Allow customers to view their connected repositories in the dashboard
- Installation access tokens: Enable the owner to access customer repositories for manual documentation generation
The system uses GitHub's OAuth 2.0 protocol combined with GitHub App installation to bridge payment to repository access. For payment processing details, see Payment Processing. For the admin panel that generates installation tokens, see Admin Panel. For the automation scripts that use these tokens, see Automation System.
Dual Authentication ArchitectureLink copied!
The authentication system maintains clear separation between user capabilities and owner capabilities through distinct token types and authentication flows.
Dual Authentication Model
Key Architectural Principles:
| Aspect | User Path | Owner Path |
|---|---|---|
| Authentication Method | OAuth 2.0 authorization code flow | GitHub App JWT + installation token |
| Token Storage | HTTP-only cookie (github_access_token) | Not stored (generated on-demand) |
| Token Lifespan | 24 hours | 1 hour |
| Access Scope | User's own repositories | Customer's shared repositories |
| Credentials Used | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET | GITHUB_APP_ID, GITHUB_PRIVATE_KEY |
| Primary Use Case | Dashboard viewing | Repository cloning and access |
Sources: app/api/auth/github/route.ts L1-L44
app/api/auth/github/callback/route.ts L1-L149
OAuth Initiation FlowLink copied!
The OAuth flow begins at /api/auth/github, which constructs the GitHub App installation URL with embedded state parameters for CSRF protection and payment correlation.
OAuth Initiation Route Handler
State Parameter Construction:
The state parameter encodes two critical pieces of information:
const stateData = { uuid: crypto.randomUUID(), // CSRF protection sessionId: sessionId || null, // Payment correlation}const state = Buffer.from(JSON.stringify(stateData)).toString('base64')
Implementation Details:
| Component | Purpose | Location |
|---|---|---|
GITHUB_APP_SLUG | Identifies the GitHub App (e.g., godeepwiki-github-integration) | app/api/auth/github/route.ts L5 |
github_oauth_state cookie | Stores state for verification in callback | app/api/auth/github/route.ts L29-L34 |
session_id query parameter | Links payment to GitHub connection | app/api/auth/github/route.ts L13 |
| State encoding | Base64-encoded JSON with UUID and session ID | app/api/auth/github/route.ts L16-L20 |
Cookie Configuration:
cookieStore.set("github_oauth_state", state, { path: "/", secure: process.env.NODE_ENV === "production", // HTTPS only in production httpOnly: true, // Prevents XSS access maxAge: 60 * 60, // 1 hour expiry})
Sources: app/api/auth/github/route.ts L1-L44
GitHub App Installation FlowLink copied!
When users click "Connect GitHub" on the success page, they are redirected to the GitHub App installation page where they select repositories and grant permissions.
GitHub App Installation Process
Repository Selection Security:
The system strongly recommends users select "Only select repositories" during installation, though this is a user choice, not an app-level configuration:
| Selection Option | Security Impact | Recommendation |
|---|---|---|
| Only select repositories | Limits access to explicitly chosen repos | ✅ Recommended |
| All repositories | Grants access to all current and future repos | ⚠️ Not recommended |
GitHub App Permissions:
The app requests minimal read-only permissions:
| Permission Type | Level | Purpose |
|---|---|---|
| Contents | Read | Access repository files for cloning |
| Metadata | Read | Access repository details (name, URL, etc.) |
| Email addresses (Account) | Read | Identify customer for email delivery |
Critical OAuth Setting:
The GitHub App must have "Request user authorization (OAuth) during installation" enabled. This setting causes GitHub to return both installation_id AND code in the same callback, enabling the system to:
- Authenticate the user via OAuth (
code) - Link to the GitHub App installation (
installation_id) - Store the user token for dashboard access
- Log the installation for owner access
Sources: README.md L102-L149
github-app-description.md L1-L46
OAuth Callback HandlerLink copied!
The callback handler at /api/auth/github/callback is the most complex component, responsible for state verification, token exchange, user data fetching, installation logging, and ntfy notification dispatch.
Callback Handler Flow
State Verification (CSRF Protection):
// Retrieve state from URL and cookieconst state = searchParams.get("state")const storedState = cookieStore.get("github_oauth_state")?.value// Verify matchif (!state || !storedState || state !== storedState) { return new Response("Invalid state", { status: 400 })}
Session ID Extraction:
The callback decodes the state parameter to extract the Stripe session ID:
const stateData = JSON.parse(Buffer.from(state, 'base64').toString('utf-8'))stripeSessionId = stateData.sessionId // Links to payment
Token Exchange Process:
| Step | Endpoint | Purpose |
|---|---|---|
| 1. Exchange code | POST https://github.com/login/oauth/access_token | Convert authorization code to access token |
| 2. Fetch user data | GET https://api.github.com/user | Retrieve username, email, user ID |
| 3. Store token | Set github_access_token cookie | Enable dashboard access |
Installation Logging:
When installation_id is present, the callback logs comprehensive details for owner correlation:
🎉 NEW GITHUB APP INSTALLATION
Stripe Session ID: cs_test_xxx
Installation ID: 12345678
GitHub Username: customer-username
GitHub Email: customer@example.com
GitHub User ID: 98765432
User Name: Customer Name
Setup Action: install
Timestamp: 2024-01-15T10:30:00.000Z
ntfy Notification Dispatch:
The callback sends a notification to ntfy.sh to trigger automation:
const message = `✅ GitHub Connected!🔑 Installation ID: ${installationId}📧 Customer: ${customerEmail}🔑 Match ID: ${sessionShort} // Last 12 chars of session_id⏰ Time: ${timestamp}🤖 Automation will now:• Clone the repository• Create private repo in your accountCheck terminal for progress!`
User Token Cookie Configuration:
cookieStore.set("github_access_token", data.access_token, { path: "/", secure: process.env.NODE_ENV === "production", httpOnly: true, // XSS protection maxAge: 60 * 60 * 24, // 24 hours})
Sources: app/api/auth/github/callback/route.ts L1-L149
Token Types and LifespansLink copied!
The system uses two distinct token types with different lifespans, purposes, and generation mechanisms.
Token Type Comparison
| Aspect | User OAuth Token | Installation Access Token |
|---|---|---|
| Purpose | Dashboard access to user's own repos | Owner access to customer's shared repos |
| Generation | OAuth authorization code flow | GitHub App JWT authentication |
| Lifespan | 24 hours | 1 hour |
| Storage | github_access_token cookie | Not stored (ephemeral) |
| Renewal | User must re-authenticate | Generated on-demand via admin panel |
| Scope | read:user user:email | Repository-level (installation scoped) |
| Use Case | /dashboard page | Repository cloning, GitHub API calls |
| Generated By | GitHub OAuth server | GitHub App API |
| Credentials Required | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET | GITHUB_APP_ID, GITHUB_PRIVATE_KEY |
User OAuth Token Lifecycle:
Installation Access Token Lifecycle:
Token Security Characteristics:
| Security Feature | User OAuth Token | Installation Access Token |
|---|---|---|
| HTTP-Only | ✅ Yes (XSS protection) | N/A (not stored in browser) |
| Secure Flag | ✅ Yes (production HTTPS) | N/A |
| Short Lifespan | ⚠️ 24 hours | ✅ 1 hour (minimal exposure) |
| Revocable | ✅ User can revoke via GitHub | ✅ Auto-expires after 1 hour |
| Encrypted in Transit | ✅ HTTPS | ✅ HTTPS |
Token Usage Examples:
User OAuth Token (Dashboard):
// In /dashboard pageconst cookieStore = await cookies()const token = cookieStore.get("github_access_token")?.valueconst response = await fetch("https://api.github.com/user/repos", { headers: { Authorization: `Bearer ${token}`, Accept: "application/vnd.github.v3+json", },})
Installation Access Token (Automation):
# Generated via /api/admin/generate-token# Used in automation scriptsgit clone https://oauth2:$INSTALLATION_TOKEN@github.com/customer/repo.git
Sources: app/api/auth/github/callback/route.ts L90-L96
Payment-to-Installation CorrelationLink copied!
The system links Stripe payments to GitHub installations through the session_id parameter, which flows through the OAuth state mechanism and is logged for manual correlation.
Correlation Flow Diagram
State Parameter Encoding:
The session_id from Stripe is embedded in the OAuth state parameter:
| Stage | Data Structure | Format |
|---|---|---|
| Input | session_id from URL parameter | cs_test_a1b2c3d4e5f6... |
| Encoding | {uuid: "...", sessionId: "cs_test_a1b2c3d4e5f6..."} | JSON object |
| State Parameter | Base64-encoded JSON | eyJ1dWlkIjoiLi4uIiwic2Vzc2lvbklkIjoiY3NfdGVzdF9hMWIyYzNkNGU1ZjYifQ== |
| Cookie Storage | Same Base64 string | Stored as github_oauth_state cookie |
Correlation Logging:
The callback logs all correlation data to Vercel logs:
Stripe Session ID: cs_test_a1b2c3d4e5f6g7h8i9j0
Installation ID: 12345678
GitHub Username: customer-username
GitHub Email: customer@example.com
Timestamp: 2024-01-15T10:30:00.000Z
Match ID Mechanism:
The ntfy notification includes a "Match ID" (last 12 characters of session_id) for quick visual correlation:
const sessionShort = stripeSessionId ? stripeSessionId.slice(-12) : 'Not linked'// Example: cs_test_a1b2c3d4e5f6 → d4e5f6
Manual Correlation Workflow:
- Owner receives payment in Stripe Dashboard → notes
session_id - Owner checks Vercel logs for matching
session_id - Owner finds corresponding
installation_idin logs - Owner uses
installation_idin/adminpanel to generate access token - Owner clones customer repository for manual documentation
Why Manual Correlation:
The system does not use a database to automatically link payments to installations. This design choice:
- ✅ Simplifies architecture (no database required)
- ✅ Reduces operational complexity
- ✅ Works well for low-volume operations
- ⚠️ Requires manual log inspection
- ⚠️ Would be bottleneck at high scale
Sources: app/api/auth/github/route.ts L11-L24
app/api/auth/github/callback/route.ts L39-L50
app/api/auth/github/callback/route.ts L98-L121
Environment Variables for AuthenticationLink copied!
The authentication system requires multiple environment variables for both OAuth and GitHub App authentication.
Required Environment Variables
| Variable | Purpose | Used By | Example |
|---|---|---|---|
GITHUB_APP_SLUG | GitHub App identifier in URLs | OAuth initiation | godeepwiki-github-integration |
GITHUB_CLIENT_ID | OAuth client identifier | OAuth flow | Iv1.a1b2c3d4e5f6g7h8 |
GITHUB_CLIENT_SECRET | OAuth client secret | Token exchange | a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 |
GITHUB_APP_ID | GitHub App numeric ID | Installation token generation | 123456 |
GITHUB_PRIVATE_KEY | GitHub App private key (PEM) | JWT signing for installation tokens | -----BEGIN RSA PRIVATE KEY-----\n... |
GITHUB_WEBHOOK_SECRET | Webhook signature verification | /api/webhooks/github | a1b2c3d4e5f6... |
NTFY_TOPIC | ntfy.sh notification topic | Automation trigger | klaudioz-codex-alerts-xxx |
Obtaining GitHub App Credentials:
Step 1: App ID and Client ID
- Navigate to:
https://github.com/organizations/YOUR_ORG/settings/apps/YOUR_APP_SLUG - Found in "About" section
Step 2: Client Secret
- Generate in "Client secrets" section
- Copy immediately (shown only once)
Step 3: Private Key
- Scroll to "Private keys" section
- Click "Generate a private key"
- Download
.pemfile - For Vercel: Use multiline string with actual line breaks
- For local
.env: Convert to base64 or use multiline string
Step 4: Webhook Secret
- Generate:
openssl rand -hex 32 - Set in GitHub App webhook configuration
- Store in
GITHUB_WEBHOOK_SECRET
Environment Variable Usage Map:
Sources: README.md L73-L91
Security ConsiderationsLink copied!
The authentication system implements multiple security layers to protect user credentials and prevent common attacks.
Security Features Summary
| Attack Vector | Mitigation Strategy | Implementation |
|---|---|---|
| CSRF (Cross-Site Request Forgery) | OAuth state parameter with UUID | app/api/auth/github/route.ts L17 |
| XSS (Cross-Site Scripting) | HTTP-only cookies | app/api/auth/github/callback/route.ts L94 |
| Man-in-the-Middle | HTTPS with Secure cookie flag | app/api/auth/github/callback/route.ts L93 |
| Token Theft | Short token lifespans (1 hour for installation tokens) | Design decision |
| Unauthorized Access | Read-only repository permissions | GitHub App configuration |
| Session Hijacking | Cookie-based state verification | app/api/auth/github/callback/route.ts L32-L35 |
| Replay Attacks | State token deleted after use | app/api/auth/github/callback/route.ts L37 |
State Parameter Security Flow:
Cookie Security Configuration:
| Property | Value | Security Benefit |
|---|---|---|
httpOnly | true | Prevents JavaScript access (XSS mitigation) |
secure | true (production) | Forces HTTPS transmission |
maxAge | 3600 (1 hour for state), 86400 (24 hours for token) | Limits exposure window |
path | / | Restricts cookie scope |
sameSite | Default (Lax) | CSRF protection for top-level navigation |
Least Privilege Principle:
The GitHub App requests minimal permissions:
- Contents: Read (not Write) → Cannot modify customer code
- Metadata: Read → Basic repository information only
- No admin permissions → Cannot change repository settings
- User selects repositories → Access limited to chosen repos only
Token Exposure Mitigation:
| Token Type | Exposure Risk | Mitigation |
|---|---|---|
| User OAuth Token | Stored in browser cookie | HTTP-only, Secure flag, 24-hour expiry |
| Installation Token | Not stored | 1-hour expiry, generated on-demand, ephemeral |
| GitHub Client Secret | Server-side only | Never exposed to client |
| GitHub Private Key | Server-side only | Never exposed to client |
Known Security Limitations:
⚠️ Admin Password Exposure: NEXT_PUBLIC_ADMIN_PASSWORD is exposed to the client (due to NEXT_PUBLIC_ prefix). This is a simplified security model suitable for low-volume operations but not enterprise-grade. See Admin Authentication for details.
⚠️ No Rate Limiting: The system does not implement rate limiting on authentication endpoints, making it vulnerable to brute-force attacks on the admin panel.
Sources: app/api/auth/github/route.ts L29-L34
app/api/auth/github/callback/route.ts L91-L96
Refresh this wiki
Last indexed: 23 November 2025 (922b35)
On this page
- Authentication & GitHub Integration
- Purpose and Scope
- Dual Authentication Architecture
- OAuth Initiation Flow
- GitHub App Installation Flow
- OAuth Callback Handler
- Token Types and Lifespans
- Payment-to-Installation Correlation
- Environment Variables for Authentication
- Security Considerations
Ask Devin about godeep.wiki-jb